<!DOCTYPE html><html class="appearance-auto" lang="zh-CN"><head><meta charset="UTF-8"><title>【Spring源码解析系列】 ApplicationListener</title><meta name="description" content="用创业者心态做好每一件事情！"><meta name="viewport" content="width=device-width, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no, initial-scale=1"><!-- Google Analytics --><!-- End Google Analytics -->
<!-- Baidu Analytics --><!-- End Baidu Analytics --><link rel="icon" href="/blog/images/favicon.png"><link rel="stylesheet" href="/blog/style/common/bulma.css"><link rel="stylesheet" href="/blog/style/base.css"><link rel="stylesheet" href="/blog/style/common/helper.css"><script src="/blog/js/common.js"></script><link rel="stylesheet" href="/blog/style/post.css"><link rel="stylesheet" href="/blog/style/themes/highlight-theme-light.css"><script src="/blog/js/highlight.pack.js"></script><meta name="description" content="
本文主要讲述Spring三大扩展功能之：ApplicationListener


作用在开发时有时候需要在整个应用开始运行时执行一些特定代码，比如初始化环境，准备测试数据、加载一些数据到内存等等。ApplicationContext事件机制是观察者设计模式的实现，通过ApplicationEvent类和ApplicationListener接口，可以实现ApplicationContext事件处理。如果容器中有一个ApplicationListener Bean，每当ApplicationContext发布ApplicationEvent时，ApplicationListener Bean将自动被触发。这种事件机制都必须需要程序显示的触发。
内置事件


Spring内置事件
描述



Context.."><!-- hexo injector head_end start -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.12.0/dist/katex.min.css">

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/hexo-math@4.0.0/dist/style.css">
<!-- hexo injector head_end end --><meta name="generator" content="Hexo 5.4.1"><link rel="alternate" href="/blog/atom.xml" title="janedler's blog" type="application/atom+xml">
</head><body class="is-flex is-flex-direction-column"><header class="header-widget is-flex-shrink-0 is-hidden-mobile"><div class="container is-fullhd is-flex is-justify-content-space-between is-align-items-center is-full-height"><section class="is-hidden-mobile is-flex-shrink-0"><h2><a href="/blog/">田园牧歌(*︶*)'s blog</a></h2></section><h3 class="is-hidden-mobile is-family-serif is-full-height is-flex is-align-items-center is-flex-shrink-0"><div class="is-full-height" id="postTopic"><p class="is-full-height is-flex-shrink-0 is-flex is-align-items-center is-justify-content-center">【Spring源码解析系列】 ApplicationListener</p><p class="is-full-height is-flex-shrink-0 is-flex is-align-items-center is-justify-content-center">点击返回顶部</p></div></h3><aside class="is-flex-shrink-0"><h3 class="is-inline-block"><a href="/blog/">首页</a></h3><h3 class="is-inline-block"><a href="/blog/about">关于</a></h3><h3 class="is-inline-block"><a href="/blog/archives">归档</a></h3></aside></div></header><header class="is-flex header-widget is-flex-shrink-0 is-align-items-center is-justify-content-center is-hidden-tablet"><h3 class="is-inline-block"><a href="/blog/">首页</a></h3><h3 class="is-inline-block"><a href="/blog/about">关于</a></h3><h3 class="is-inline-block"><a href="/blog/archives">归档</a></h3></header><main><main class="container is-max-widescreen content section post-page pt-4 px-4"><div class="columns is-flex-desktop is-justify-content-center is-flex-direction-row-reverse"><div class="column is-3 is-hidden-mobile"><ol class="toc"><li class="toc-item toc-level-2"><a class="toc-link" href="#%E4%BD%9C%E7%94%A8"><span class="toc-text">作用</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%86%85%E7%BD%AE%E4%BA%8B%E4%BB%B6"><span class="toc-text">内置事件</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E7%A4%BA%E4%BE%8B"><span class="toc-text">示例</span></a></li></ol></div><div class="column is-9"><header class="my-4"><a href="/blog/tags/Java"><i class="tag post-item-tag">Java</i></a><a href="/blog/tags/Spring"><i class="tag post-item-tag">Spring</i></a></header><h1 class="mt-0 mb-1 is-family-serif" id="postTitle">【Spring源码解析系列】 ApplicationListener</h1><time class="has-text-grey" datetime="2022-11-28T16:00:00.000Z">2022-11-29</time><article class="mt-2 post-content"><p><img src="https://janedler.oss-cn-beijing.aliyuncs.com/images/spring.png" alt="cover"></p>
<p>本文主要讲述Spring三大扩展功能之：ApplicationListener</p>
<span id="more"></span>

<h2 id="作用"><a href="#作用" class="headerlink" title="作用"></a>作用</h2><p>在开发时有时候需要在<strong>整个应用开始运行时执行一些特定代码</strong>，比如初始化环境，准备测试数据、加载一些数据到内存等等。<br>ApplicationContext事件机制是<strong>观察者设计模式</strong>的实现，通过ApplicationEvent类和ApplicationListener接口，可以实现ApplicationContext事件处理。<br>如果容器中有一个ApplicationListener Bean，每当ApplicationContext发布ApplicationEvent时，ApplicationListener Bean将自动被触发。这种事件机制都必须需要程序显示的触发。</p>
<h2 id="内置事件"><a href="#内置事件" class="headerlink" title="内置事件"></a>内置事件</h2><table>
<thead>
<tr>
<th>Spring内置事件</th>
<th>描述</th>
</tr>
</thead>
<tbody><tr>
<td>ContextRefreshedEvent</td>
<td>ApplicationContext 被初始化或刷新时，该事件被发布。这也可以在 ConfigurableApplicationContext接口中使用 refresh() 方法来发生。此处的初始化是指：所有的Bean被成功装载，后处理Bean被检测并激活，所有Singleton Bean 被预实例化，ApplicationContext容器已就绪可用。</td>
</tr>
<tr>
<td>ContextStartedEvent</td>
<td>当使用 ConfigurableApplicationContext （ApplicationContext子接口）接口中的 start() 方法启动 ApplicationContext 时，该事件被发布。你可以调查你的数据库，或者你可以在接受到这个事件后重启任何停止的应用程序。</td>
</tr>
<tr>
<td>ContextStoppedEvent</td>
<td>当使用 ConfigurableApplicationContext 接口中的 stop() 停止 ApplicationContext 时，发布这个事件。你可以在接受到这个事件后做必要的清理的工作。</td>
</tr>
<tr>
<td>ContextClosedEvent</td>
<td>当使用 ConfigurableApplicationContext 接口中的 close() 方法关闭 ApplicationContext 时，该事件被发布。一个已关闭的上下文到达生命周期末端；它不能被刷新或重启。</td>
</tr>
<tr>
<td>RequestHandledEvent</td>
<td>这是一个 web-specific 事件，告诉所有 bean HTTP 请求已经被服务。只能应用于使用DispatcherServlet的Web应用。在使用Spring作为前端的MVC控制器时，当Spring处理用户请求结束后，系统会自动触发该事件。</td>
</tr>
</tbody></table>
<h2 id="示例"><a href="#示例" class="headerlink" title="示例"></a>示例</h2><pre><code class="java">public class EmailEvent extends ApplicationEvent &#123;

    private String address;

    private String text;

    public EmailEvent(Object source) &#123;
        super(source);
    &#125;

    public EmailEvent(Object source, String address, String text)&#123;
        super(source);
        this.address = address;
        this.text = text;
    &#125;

    ...get set...
&#125;
</code></pre>
<pre><code class="java">@Component
//public class NotifyListener implements ApplicationListener&lt;EmailEvent&gt;
public class NotifyListener implements ApplicationListener &#123;

    @Override
    public void onApplicationEvent(ApplicationEvent event) &#123;
        if (event instanceof EmailEvent) &#123;
            EmailEvent emailEvent = (EmailEvent)event;
            System.out.println(&quot;邮件地址：&quot; + emailEvent.getAddress());
            System.out.println(&quot;邮件内容：&quot; + emailEvent.getText());
        &#125;else&#123;
            System.out.println(&quot;容器本身事件：&quot; + event);
        &#125;
    &#125;
&#125;
</code></pre>
<pre><code class="xml">&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;beans xmlns=&quot;http://www.springframework.org/schema/beans&quot;
       xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
       xmlns:context=&quot;http://www.springframework.org/schema/context&quot;
       xsi:schemaLocation=&quot;
       http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd&quot;&gt;
    &lt;context:component-scan base-package=&quot;org.janedler&quot;/&gt;

    &lt;bean class=&quot;org.janedler.NotifyListener&quot;&gt;&lt;/bean&gt;

&lt;/beans&gt;
</code></pre>
<pre><code class="java">ApplicationContext context = new ClassPathXmlApplicationContext(&quot;applicationContext.xml&quot;);
//创建一个ApplicationEvent对象
EmailEvent event = new EmailEvent(&quot;hello&quot;,&quot;abc@163.com&quot;,&quot;This is a test&quot;);
//主动触发该事件
context.publishEvent(event);
</code></pre>
<pre><code class="bash">容器本身事件：org.springframework.context.event.ContextRefreshedEvent[source=org.springframework.context.support.ClassPathXmlApplicationContext@197848c: startup date [Thu Dec 01 14:01:41 CST 2022]; root of context hierarchy]
容器本身事件：org.springframework.context.event.ContextRefreshedEvent[source=org.springframework.context.support.ClassPathXmlApplicationContext@197848c: startup date [Thu Dec 01 14:01:41 CST 2022]; root of context hierarchy]
邮件地址：abc@163.com
邮件内容：This is a test
邮件地址：abc@163.com
邮件内容：This is a test
</code></pre>
</article><section class="jump-container is-flex is-justify-content-space-between my-6"><!-- em is empty placeholder--><a class="button is-default" href="/blog/2022/12/01/Spring/Spring-BeanFactory/" title="【Spring源码解析系列】 FactoryBean"><i class="iconfont icon-prev mr-2 has-text-grey"></i><span class="has-text-weight-semibold">上一页: 【Spring源码解析系列】 FactoryBean</span></a><a class="button is-default" href="/blog/2022/11/29/Spring/Spring%E8%A7%A3%E5%86%B3%E5%BE%AA%E7%8E%AF%E4%BE%9D%E8%B5%96/" title="【Spring源码解析系列】 Spring解决循环依赖"><span class="has-text-weight-semibold">下一页: 【Spring源码解析系列】 Spring解决循环依赖</span><i class="iconfont icon-next ml-2 has-text-grey"></i></a></section><article class="mt-6 comment-container"><script async repo="janedler/blog" src="https://utteranc.es/client.js" issue-term="pathname" theme="preferred-color-scheme"></script></article></div></div></main></main><footer class="is-flex is-flex-direction-column is-align-items-center is-flex-shrink-0 is-family-serif"><section class="sns-container"><!-- Github--><a title="github" target="_blank" rel="noopener nofollow" href="//github.com//janedler"><i class="iconfont icon-github"></i></a><!-- Ins--><!-- RSS--><a title="rss" target="_blank" rel="noopener nofollow" href="/blog/atom.xml"><i class="iconfont icon-rss"></i></a><!-- 知乎--><!-- 领英--><!-- 脸书--></section><p><span>Copyright ©</span><span> 田园牧歌(*︶*) 2022</span></p><div class="is-flex is-justify-content-center is-flex-wrap-wrap"><p>Powered by Hexo &verbar;&nbsp;</p><p class="is-flex is-justify-content-center"><a title="Hexo theme author" target="_blank" rel="noopener" href="//github.com/haojen">Theme by Haojen&nbsp;</a></p><div style="margin-top: 2px"><a class="github-button" title="github-button" target="_blank" rel="noopener" href="https://github.com/haojen/hexo-theme-Claudia" data-color-scheme="no-preference: light; light: light; dark: dark;" data-show-count="true"></a></div></div><div><span></span></div></footer><script async defer src="https://buttons.github.io/buttons.js"></script><script src="/blog/js/post.js"></script></body></html>